//netSynch.cc
// The class to keep all the locks that request to the server
#include "copyright.h"
#include "list.h"
#include "system.h"
#include "network.h"
#include "post.h"
#include "interrupt.h"
#include "netsynch.h"
#include <vector>

using namespace std;

const int arraySize = 10;
const int locksize = 10;

NetSynch::NetSynch(){
  condArray = new myCond[arraySize];
  lockArray = new myLock[arraySize];
  for(int i = 0; i<arraySize; i++){
    condArray[i].condID = -1;
    lockArray[i].lockID = -1;
    lockArray[i].lockBusy = false;
    lockArray[i].lockOwner = -1;
    // lockArray[i].lp = new List;
    //condArray[i].waitCV = new List;

    /*  for(unsigned int z=0; z<lockArray[z].lp.size(); z++){
       lockArray[i].lp.inPktHdr.from = -1;
       lockArray[i].lp.inMailHdr.from = -1;
	}
     for(unsigned int w=0; w<condArray[w].waitCV.size(); w++){
       condArray[w].waitCV.inPktHdr.from = -1;
       condArray[w].waitCV.inMailHdr.from = -1;
       }*/
  }
}



int NetSynch::Acquire(int iden, PacketHeader inPH, MailHeader inMH){
  if(iden<0){
    cout<<"Acquire lock: Bad user input\n";
    return 10000;
  }
  else {
    cout<<"lock Status: "<<lockArray[iden].lockBusy<<endl;

    if(!lockArray[iden].lockBusy){
      //if the lock is not busy
      lockArray[iden].lockBusy = true;
      lockArray[iden].lockOwner = inPH.from;
      return 0;
    }
    else{
      //if the lock is busy
      cout<<"Server: Lock "<<iden<<" is busy, wait in lockArray\n";
      lockPacket temp;
      temp.inPktHdr = inPH;
      temp.inMailHdr = inMH;
      cout<<"inPKTHDR.from "<<temp.inPktHdr.from<<endl;
      cout<<"mailHrd.from "<<temp.inMailHdr.from<<endl;
      lockArray[iden].lp.push_back(temp);
      //lockArray[iden].lp.push_back(temp);
      return 1;

    }
  }      
}

/***************************************************************************************/
/*Function to send the message from the server ******/
bool NetSynch::sendMsg(PacketHeader inPktHdr, MailHeader inMailHdr,char* data){

  PacketHeader outPktHdr;
  MailHeader outMailHdr;
 
  
  outPktHdr.to = inPktHdr.from;
  outMailHdr.to = inMailHdr.from;
  outMailHdr.from = 0;  
  outMailHdr.length = strlen(data) + 1;

  bool success = postOffice->Send(outPktHdr, outMailHdr, data); 

  return success;
}

/**********************************************************************************/
void NetSynch:: Release(int id,PacketHeader inPH, MailHeader inMH){
  cout<<"ID AT BEGINNING: "<<id<<endl;

  if(id<0){
    cout<<"Release: Bad user input\n";
   
  }
  else if (lockArray[id].lockOwner == inPH.from) {
    if(!lockArray[id].lp.empty()){  
      //if the list is empty
      if(!lockArray[id].lockBusy){
	cout<<"Release: No one owned the lock!\n";      
      }
      else{
	lockPacket* nextOwner =(lockPacket*)lockArray[id].lp.front();
	(lockPacket*)lockArray[id].lp.erase(0);
	char* nextLockOwner = "LockAcquire ACK\n";   
	bool sentLock = sendMsg(nextOwner->inPktHdr,nextOwner->inMailHdr,nextLockOwner);
	cout<<"inPKTHDR.from "<<nextOwner->inPktHdr.from<<endl;
	cout<<"mailHrd.from "<<nextOwner->inMailHdr.from<<endl;
	lockArray[id].lockOwner = nextOwner->inPktHdr.from;
	if ( !sentLock ) {
	  printf("The postOffice Send failed. You must not have the other Nachos running. Terminating Nachos.\n");
	  interrupt->Halt();
	}
	else{
	  cout<<"SENT Lock to Next Owner\n";
	}
      }
    }
    else {
      cout<<"NetSynch, Release: List empty, no one else is trying to acquire the lock\n";
      lockArray[id].lockBusy = false;
      lockArray[id].lockOwner = -1;
      cout<<"Lock ID: "<<id<<endl;
    }
  }
}

/**********************************************************************************/
int NetSynch::createLock(int i){
  if(i<0)
     cout<<"Create lock: Bad user input\n";
  else{
    for(int it = 0; it <arraySize; it++){
      if(lockArray[it].lockID == i){
	//lock already exist
	cout<<"Lock already created\n";
	return it;
	
      }
    }
    for(int it = 0; it<arraySize; it++){
      if(lockArray[it].lockID == -1){
	cout<<"Creating lock\n";
	lockArray[it].lockID = i;
	return it;
      }
    }
  }
  return -1;
}
/********************************************************************************/
void NetSynch::destroyLock(int i){

}


/******************************************************************************/
int NetSynch::createCondition(int i){
  if(i<0)
     cout<<"Create condition: Bad user input\n";
  else{
    for(int it = 0; it <arraySize; it++){
      if(condArray[it].condID == i){
	//lock already exist
	cout<<"Condition already created\n";
	return it;
	
      }
    }
    for(int it = 0; it<arraySize; it++){
      if(condArray[it].condID == -1){
	cout<<"Creating condition\n";
	condArray[it].condID = i;
	return it;
      }
    }
  }
  return -1;
}
/*******************************************************************************/
void NetSynch::Wait(int lID, int cID, PacketHeader inPH, MailHeader inMH){
  if(lID <0 || cID <0)
    cout<<"Wait: Bad user input";
  else{
    if(lockArray[lID].lockID == -1)
      cout<<"Wait: Bad lock input\n";
    else if(condArray[cID].condID == -1)
      cout<<"Wait: Bad condition input\n";
    else{ 
     
      lockPacket temp;
      temp.inPktHdr = inPH;
      temp.inMailHdr = inMH;
      cout<<"inPKTHDR.from "<<temp.inPktHdr.from<<endl;
      cout<<"mailHrd.from "<<temp.inMailHdr.from<<endl;
      condArray[cID].waitCV.push_back(temp);


	//condArray[cID].waitCV.push_back(tempmm);
      cout<<"After put to the wait list\n";
      Release(lID,inPH,inMH);
      cout<<"Wait: Release the lock and put myself into wait list\n";
    }
  }
}

/****************************************************************************/
void NetSynch::Signal(int lID,int cID, PacketHeader inPH ){
  if(lID<0||cID<0)
    cout<<"Signal: Bad user input\n";
  else{    
    if(lockArray[lID].lockID == -1)
      cout<<"Wait: Bad lock input\n";
    else if(condArray[cID].condID == -1)
      cout<<"Wait: Bad condition input\n";
    else if (lockArray[lID].lockOwner == inPH.from) {
      if(!condArray[cID].waitCV.empty()){
	cout<<"list not empty\n";
	lockPacket *nextOwners = (lockPacket*)condArray[cID].waitCV.front();
	(lockPacket*)condArray[cID].waitCV.erase(0);
	char* nextWait = "Sendin SignalACK\n";	
	cout<<"inPKTHDR.from "<<nextOwners->inPktHdr.from<<endl;
	cout<<"mailHrd.from "<<nextOwners->inMailHdr.from<<endl;
	int temp = Acquire(lID,nextOwners->inPktHdr,nextOwners->inMailHdr);
      }else{
	cout<<"Wait CV list is empty!";
      }
    }
  }
}
/**********************************************************************/
